#include <stdio.h>
#include <getopt.h>

// dump.c

#define NO_DISPLAY_HEX 1
#define DISPLAY_CHAR   2
#define PARAM_IS_HEX   4

void usage( char **argv ) {

  printf( "usage : %s [options] <binary file>\n", argv[ 0 ] ) ;
  printf( "\n" ) ;
  printf( "[options]\n" ) ;
  printf( "  -h : show this message and exit.\n" ) ;
  printf( "  -n : not display hex data.\n" ) ;
  printf( "  -s : display characters.\n" ) ;
  return ;

}


int main( int argc, char **argv ) {

  FILE *fp ;
  int c, opt ;
  unsigned int i = 0, flag = 0, opt_count = 0 ;
  char buffer[17] ;
  buffer[16] = 0 ;

  while( ( opt = getopt( argc, argv, "hns" ) ) != -1 ) {
    switch( opt ) {
      case 'h' :
        usage( argv ) ;
        return 0 ;
      case 'n' :
        flag |= NO_DISPLAY_HEX | DISPLAY_CHAR ;
        opt_count++ ;
        break ;
      case 's' :
        flag |= DISPLAY_CHAR ;
        opt_count++ ;
        break ;
      default :
        usage( argv ) ;
        return -1 ;
    }
  }

  if( argc - opt_count != 2 ) {
    usage( argv ) ;
    return -1 ;
  }

  if( ! ( fp = fopen( argv[ optind ], "rb" ) ) ) {
    printf( "failed to open file.\n" ) ;
    return -1 ;
  }

  while( ( c = getc( fp ) ) != EOF ) {

    if( i % 16 == 0 ) {
      printf( "%05X :", i ) ;
    }

    if( ! ( flag & NO_DISPLAY_HEX ) )
      printf( " %02X", c ) ;

    // it might be better to use if( flag & DISPLAY_CHAR )
    if( c > 32 && c < 127 ) {
      buffer[ i % 16 ] = c ;
    } else {
      buffer[ i % 16 ] = '.' ;
    }

    if( i % 16 == 15 ) {
      if( flag & DISPLAY_CHAR ) {
        printf( " %s", buffer ) ;
      }
      printf( "\n" ) ;
    }

    i++ ;

  }

  if( i % 16 != 0 ) {
    while( i % 16 != 0 ) {
      if( ! ( flag & NO_DISPLAY_HEX ) )
        printf( "   " ) ;
      buffer[ i % 16 ] = 0x20 ;
      i++ ;
    }
    if( flag & DISPLAY_CHAR ) {
      printf( " %s", buffer ) ;
    }
    printf( "\n" ) ;
  }

  fclose( fp ) ;

  return 0 ;

}

